#include "Triangle.h"

double minimum (double d1, double d2, double d3) {
	return d1<d2?(d1<d3?d1:d3):(d2<d3?d2:d3);
}
double maximum (double d1, double d2, double d3) {
	return d1>d2?(d1>d3?d1:d3):(d2>d3?d2:d3);
}
Triangle::Triangle(const Point &a, const Point &b, const Point &c):
		pA(a.getX(), a.getY(), a.getZ()), pB(b.getX(), b.getY(), b.getZ()), pC(c.getX(), c.getY(), c.getZ()) {
	normale = Vecteur(pA,pB).prodVect(Vecteur(pA,pC));
	normale.normaliser();
	double d = -normale.getX()*pA.getX() - normale.getY()*pA.getY() - normale.getZ()*pA.getZ();
	plan = Plan(normale.getX(), normale.getY(), normale.getZ(), d);
	// boite englobante
	double xMin = minimum (pA.getX(), pB.getX(), pC.getX());
	double yMin = minimum (pA.getY(), pB.getY(), pC.getY());
	double zMin = minimum (pA.getZ(), pB.getZ(), pC.getZ());
	double xMax = maximum (pA.getX(), pB.getX(), pC.getX());
	double yMax = maximum (pA.getY(), pB.getY(), pC.getY());
	double zMax = maximum (pA.getZ(), pB.getZ(), pC.getZ());
	boite = BoiteEnglobante(xMax-xMin, yMax-yMin, zMax-zMin, Point(xMin+(xMax-xMin)/2, yMin+(yMax-yMin)/2, zMin+(zMax-zMin)/2));
}
void Triangle::setNormale (Vecteur & n){
	normale = n;
	double d = -normale.getX()*pA.getX() - normale.getY()*pA.getY() - normale.getZ()*pA.getZ();
	plan = Plan(normale.getX(), normale.getY(), normale.getZ(), d);
}
void Triangle::intersection(const Rayon &r, Intersection & intersectRetour) {
	// calcul de l'intersection entre le rayon et le plan contenant le triangle
	plan.intersection(r, intersectRetour);
	if (intersectRetour.isNull()) {
		return;
	}
	Point origineRayon = r.getOrigine();
	Vecteur directionRayon = r.getDirection();
	// le point d'intersection appartient-il au triangle ?
	Vecteur n1 = Vecteur(origineRayon, pB).prodVect(Vecteur(origineRayon, pA));
	Vecteur n2 = Vecteur(origineRayon, pC).prodVect(Vecteur(origineRayon, pB));
	Vecteur n3 = Vecteur(origineRayon, pA).prodVect(Vecteur(origineRayon, pC));
	n1.normaliser();
	n2.normaliser();
	n3.normaliser();
	if (n1.prodScal(directionRayon) < 0 || n2.prodScal(directionRayon) < 0 || n3.prodScal(directionRayon) < 0) {
		intersectRetour.setNull(true);
		return;
	}
	intersectRetour.setObjet(this);
	intersectRetour.setNull(false);
}
bool Triangle::ombre(const Rayon &r, double distance) {
	// calcul de l'intersection entre le rayon et le plan contenant le triangle
	Intersection i;
	plan.intersectionBiface(r, i);
	if (i.isNull() || i.getDistance()>distance) {
		return false;
	}
	Point origineRayon = r.getOrigine();
	Vecteur directionRayon = r.getDirection();
	// le point d'intersection appartient-il au triangle ?
	Vecteur n1;
	Vecteur n2;
	Vecteur n3;
	if (r.getDirection().prodScal(normale) > 0)  {
		n1 = Vecteur(origineRayon, pA).prodVect(Vecteur(origineRayon, pB));
		n2 = Vecteur(origineRayon, pB).prodVect(Vecteur(origineRayon, pC));
		n3 = Vecteur(origineRayon, pC).prodVect(Vecteur(origineRayon, pA));
	}
	else {
		n1 = Vecteur(origineRayon, pB).prodVect(Vecteur(origineRayon, pA));
		n2 = Vecteur(origineRayon, pC).prodVect(Vecteur(origineRayon, pB));
		n3 = Vecteur(origineRayon, pA).prodVect(Vecteur(origineRayon, pC));
	}
	n1.normaliser();
	n2.normaliser();
	n3.normaliser();
	if (n1.prodScal(directionRayon) < 0 || n2.prodScal(directionRayon) < 0 || n3.prodScal(directionRayon) < 0) {
		return false;
	}
	return true;
}
